package com.tengju.bff.interfaces.app.motivation.facade;

import com.beust.jcommander.internal.Lists;
import com.tengju.bff.interfaces.app.motivation.assembler.UpgradeDetailAssembler;
import com.tengju.bff.interfaces.app.motivation.assembler.UpgradeIndicatorAssembler;
import com.tengju.bff.interfaces.app.motivation.vo.UpgradeDetailVO;
import com.tengju.bff.interfaces.app.motivation.vo.UpgradeIndicatorVO;
import com.tengju.data.application.star.StarIndicatorService;
import com.tengju.data.domain.model.user.StarIndicator;
import com.tengju.data.domain.model.user.UserIdCode;
import com.tengju.support.application.rule.RuleService;
import com.tengju.support.application.shared.ApplicationException;
import com.tengju.support.application.shared.ApplicationExceptionCode;
import com.tengju.support.domain.model.rule.RuleId;
import com.tengju.support.domain.model.rule.UpgradeHintMetaInfo;
import com.tengju.support.domain.model.rule.UpgradeIndexMetaInfo;
import com.tengju.user.domain.model.sign.StarSignInfo;
import com.tengju.user.domain.model.sign.StarSignInfoRepository;
import com.tengju.user.domain.model.star.StarIndicatorType;
import com.tengju.user.domain.model.user.StarLevelEnum;
import com.tengju.user.domain.model.user.UserInfo;
import com.tengju.user.domain.model.user.UserInfoRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
@Slf4j
public class UpgradeCenterFacade {

    private final StarIndicatorService starIndicatorService;
    private final UserInfoRepository userInfoRepository;
    private final RuleService ruleService;
    private final StarSignInfoRepository starSignInfoRepository;

    @Value("#{${user.upgrade.rule}}")
    private Map<String,Long> upgradeRuleMap;

    @Value("#{${user.upgrade.target.index}}")
    private Map<String,Map<Integer,Double>> targetIndexMap;

    @Value("${user.upgrade.hint.rule}")
    private Long upgradeHintRule;

    public UpgradeDetailVO upgradeDetail(UserIdCode idCode) {

        //获取目标等级
        UserInfo user = userInfoRepository
                .getByIdCode(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));
        if (user == null) {
            throw ApplicationException.error(ApplicationExceptionCode.USER_NOT_EXIST,idCode.getValue());
        }
        StarLevelEnum targetLevel = user.targetLevel();
        if (targetLevel == null) {
            return null;
        }

        //获取用户当前指标完成情况
        List<StarIndicator> currentStarIndicators =
                starIndicatorService.listMaxDayStarIndicatorStat(idCode);

        Map<StarIndicatorType, StarIndicator> currentIndexMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(currentStarIndicators)) {
            currentIndexMap = currentStarIndicators
                    .stream().collect(Collectors.toMap(StarIndicator::getStarIndicatorType, Function.identity()));
        }

        //创建metaInfo
        UpgradeIndexMetaInfo upgradeIndexMetaInfo = new UpgradeIndexMetaInfo();
        upgradeIndexMetaInfo.setTargetStarLevel(targetLevel.getCode());

        List<UpgradeIndicatorVO> upgradeIndicatorVOList = Lists.newArrayList();

        boolean totalResult = true;

        List<StarIndicatorType> allIndicatorTypes = StarIndicatorType.all();
        for (StarIndicatorType starIndicatorType : allIndicatorTypes) {
            //晋升目标值
            Map<Integer, Double> levelTarget =
                    targetIndexMap.get(starIndicatorType.getCode());
            //规则id
            Long ruleIdVal = upgradeRuleMap.get(starIndicatorType.getCode());
            //晋升目标值为-1  非当前等级晋升指标 过滤
            Double targetIndexVal = levelTarget.get(targetLevel.getCode());
            if (targetIndexVal == -1) {
                continue;
            }

            StarIndicator currentStarIndicator = currentIndexMap.get(starIndicatorType);

            BigDecimal targetIndex = BigDecimal.valueOf(targetIndexVal);
            BigDecimal currentIndex = Optional.ofNullable(currentStarIndicator)
                    .map(StarIndicator::getIndicatorValue).orElse(BigDecimal.ZERO);

            //填充metaInfo值 执行规则
            upgradeIndexMetaInfo.filledByIndexType(
                    com.tengju.support.domain.model.star.StarIndicatorType.fromVal(starIndicatorType.getCode()),
                    Optional.ofNullable(currentStarIndicator).map(StarIndicator::getIndicatorValue).map(BigDecimal::doubleValue).orElse(0d));
            boolean result = ruleService.evaluate(upgradeIndexMetaInfo, new RuleId(ruleIdVal));

            UpgradeIndicatorVO upgradeIndicatorVO =
                    UpgradeIndicatorAssembler.convertToVO(starIndicatorType, targetIndex, currentIndex, result);
            upgradeIndicatorVOList.add(upgradeIndicatorVO);

            totalResult = totalResult && result;

        }
        //获取签约中信息
        StarSignInfo signInfo = starSignInfoRepository
                .getByIdCode(new com.tengju.user.domain.model.user.UserIdCode(idCode.getValue()));

        LocalDate indicatorDay = LocalDate.MIN;
        if (!CollectionUtils.isEmpty(currentStarIndicators)) {
            indicatorDay = currentStarIndicators.get(0).getIndicatorDay();
        }

        //执行规则 获取提示信息
        UpgradeHintMetaInfo upgradeHintMetaInfo = new UpgradeHintMetaInfo(totalResult,
                targetLevel.getCode(),
                LocalDateTime.of(indicatorDay, LocalTime.MIN),
                Optional.ofNullable(signInfo).map(StarSignInfo::getInviteDate).orElse(null));
        String hint = (String) ruleService.execute(upgradeHintMetaInfo, new RuleId(upgradeHintRule)).get(0);


        return UpgradeDetailAssembler.convertToVO(
                StarLevelEnum.parseByCode(user.getStarLevel()),
                targetLevel,
                upgradeIndicatorVOList,
                hint);


    }
}
